Skip to content

Harden ObjectArrayMessage deserialization with SerializationUtil.assertFiltered#4098

Open
SunWeb3Sec wants to merge 1 commit intoapache:2.xfrom
SunWeb3Sec:harden-message-deserialization
Open

Harden ObjectArrayMessage deserialization with SerializationUtil.assertFiltered#4098
SunWeb3Sec wants to merge 1 commit intoapache:2.xfrom
SunWeb3Sec:harden-message-deserialization

Conversation

@SunWeb3Sec
Copy link
Copy Markdown

Harden ObjectArrayMessage.readObject() with SerializationUtil.assertFiltered()

Summary

Adds a single SerializationUtil.assertFiltered(in) call at the top of ObjectArrayMessage.readObject(), bringing it in line with the defensive pattern already used by ObjectMessage and ParameterizedMessage.

Change

log4j-api/.../message/ObjectArrayMessage.java

Before

private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    array = (Object[]) in.readObject();
}

After

private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
    SerializationUtil.assertFiltered(in);
    in.defaultReadObject();
    array = (Object[]) in.readObject();
}

Plus the corresponding import org.apache.logging.log4j.util.internal.SerializationUtil;.

What this PR deliberately does not do

  • Does not change the serialized wire format — ObjectArrayMessage instances produced by older versions still deserialize into a patched version, and vice versa.
  • Does not touch LocalizedMessage or FormattedMessage. They have similar gaps, but the Log4j security team scoped this request to ObjectArrayMessage only. Happy to submit follow-up PRs for those if desired.
  • Does not modify existing tests (LocalizedMessageTest#testSerialization*, FormattedMessageTest#testSerialization) that use plain ObjectInputStream, because those classes are untouched.

Tests

Added a minimal round-trip test (ObjectArrayMessageTest#testSerializableRoundTripThroughFilteredStream) that serializes and deserializes through SerialUtil, which uses FilteredObjectInputStream on Java 8 — verifying the new assertFiltered() call accepts filtered streams.

Behavioral note

On Java 8, deserializing an ObjectArrayMessage through a plain ObjectInputStream (no JEP 290 filter) now throws IllegalArgumentException instead of silently proceeding. This matches the existing behavior of ObjectMessage and ParameterizedMessage. Callers that relied on unfiltered deserialization of ObjectArrayMessage should wrap their streams in FilteredObjectInputStream, matching the project's guidance for the sibling message types.

On Java 9+, the behavior is unchanged — assertFiltered() is a no-op when a JVM-level ObjectInputFilter is active, and a warning otherwise.

Checklist

  • Single class changed (ObjectArrayMessage)
  • No wire format change
  • No new public API
  • No new dependencies
  • Unit test added
  • Changelog entry: src/changelog/.2.x.x/harden_message_deserialization.xml (type changed)

References

  • Private discussion with the Log4j security team (HackerOne report, closed as Informative — not a vulnerability; code-quality improvement welcomed).
  • Hardened siblings for reference:
    • ObjectMessage#readObject
    • ParameterizedMessage#readObject

Thanks to the Log4j security team for the clear triage.

…rtFiltered

Adds a SerializationUtil.assertFiltered(in) call at the top of
ObjectArrayMessage#readObject, bringing it in line with the defensive
pattern already used by ObjectMessage and ParameterizedMessage.

This is a defense-in-depth / consistency fix; the serialized wire
format is unchanged so instances produced by older versions continue
to round-trip.

Signed-off-by: SunWeb3Sec <infosecpt@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant